module ActiveRecord #:nodoc: 
  module Acts #:nodoc:
    module MFD
      module MultiFieldDate
        def self.included(base) # :nodoc:
          base.extend(ClassMethods)
        end

        module ClassMethods
          #<tt>:name</tt>:: Method name for parent class to access MultiFieldDate object.  
          #E.g., If you want to set a birth_date field in your Person model as your 
          #MultiFieldDate date_field -- you might choose the name "birth",
          #which then allows you to access the MultiFieldDate methods by calling 
          #person.birth.method_name
          #<tt>:options</tt>:: Required options are: 
          #<tt>:date_field</tt>:: attribute name of full date  
          #<tt>:year_field</tt>:: attribute name of year 
          #<tt>:month_field</tt>:: attribute name of month 
          #<tt>:day_field</tt>:: attribute name of day 
          #
          #E.g., 
          #<tt>multi_field_date :birth, :date_field => 'birth_date', :year_field => 'birth_year', </tt>
          #<tt>   :month_field => 'birth_month', :day_field => 'birth_day </tt>
          def multi_field_date(name, options = {})
            options = {:date_field => 'my_date',
            :year_field => 'yr', 
            :month_field => 'mo',
            :day_field => 'day' }.merge(options)

            mapping =[[options[:date_field],  'date'],
            [options[:year_field],  'year'],
            [options[:month_field], 'month'],
            [options[:day_field],   'day']]

            composed_of name, :class_name => 'ActiveRecord::Acts::MFD::MultiFieldDateClass', :mapping => mapping 

            include ActiveRecord::Acts::MFD::DateValidator
            extend  ActiveRecord::Acts::MFD::SingletonMethods

            class_eval do 
              #updates the date field see MultiFieldDateClass::update_date

              define_method "validate_and_update_#{name}_date" do
                self.send("validate_#{name}_month_and_day".to_sym)
                self.send("update_#{name}_date".to_sym)
              end

              define_method "update_#{name}_date" do
                self.send("#{options[:date_field]}=", self.send(name.to_sym).update_date)
              end

              define_method "validate_#{name}_month_and_day" do
                if self.send(options[:month_field]) && self.send(options[:day_field])
                  dy = self.send(options[:day_field])
                  mo = self.send(options[:month_field])
                  yr = self.send(options[:year_field])
                  unless ActiveRecord::Acts::MFD::DateValidator.valid_date?(yr,mo,dy)
                    msg = 'Invalid Date.  Most likely you have chosen a day that does not exist in the month you chose.'
                    self.errors.add_to_base(msg)
                  end
                end
              end

              before_save "validate_and_update_#{name}_date".to_sym

              #sets MultiFieldDateClass object's year field equal to the parent object's :year_field
              #also sets the parent object's :year_field attribute
              define_method("#{options[:year_field]}=") do |args|
                self.write_attribute("#{options[:year_field]}", args)
                unless args == ''
                  self.send(name.to_sym).instance_variable_set("@year", *args)
                end
              end

              #sets MultiFieldDateClass object's month field equal to the parent object's :month_field
              #also sets the parent object's :month_field attribute
              define_method("#{options[:month_field]}=") do |args|
                self.write_attribute("#{options[:month_field]}", args)
                unless args == ''
                  self.send(name.to_sym).instance_variable_set("@month", *args)
                end
              end

              #sets MultiFieldDateClass object's day field equal to the parent object's :day_field
              #also sets the parent object's :day_field attribute
              define_method("#{options[:day_field]}=") do |args|
                self.write_attribute("#{options[:day_field]}", args)
                unless args == ''
                  self.send(name.to_sym).instance_variable_set("@day", *args)
                end
              end
            end

          end #multi_field_date

        end #ClassMethods
      end #MultiFieldDate


    end #MFD
  end #Acts
end #ActiveRecord
